/*
 * $Id: GameMapIOUnitTest.java 23 2009-03-31 23:37:36Z aaron.day $ 
 */

package org.crazydays.gameplan.data;


import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import java.awt.image.BufferedImage;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.crazydays.gameplan.map.Coordinate;
import org.crazydays.gameplan.map.Geometry;
import org.crazydays.gameplan.map.GridType;
import org.crazydays.gameplan.map.location.Location;
import org.crazydays.gameplan.map.location.LocationType;
import org.crazydays.gameplan.test.SimpleTestCase;

/**
 * GameMapIOTestCase
 */
public class GameMapIOUnitTest extends SimpleTestCase
{

	/**
	 * Test storeImage(String,BufferedImage,ZipOutputStream).
	 * 
	 * @throws IOException
	 */
	public void testStoreImage() throws IOException
	{
		// objects
		String name = "name";

		BufferedImage image =
		        new BufferedImage(600, 800, BufferedImage.TYPE_4BYTE_ABGR);

		File zipFile = new File(getSandbox(), "testStoreImage.zip");
		ZipOutputStream zipOutputStream =
		        new ZipOutputStream(new FileOutputStream(zipFile));

		// test
		GameMapIO.storeImage(name, image, zipOutputStream);

		// verify
		zipOutputStream.close();

		ZipFile zip = new ZipFile(zipFile);
		ZipEntry entry =
		        zip.getEntry(GameMapIO.MAP_DIRECTORY + File.separator + name + "." + GameMapIO.MAP_IMAGE_EXTENSION);
		InputStream inputStream = zip.getInputStream(entry);
		BufferedImage result = GameMapIO.loadImage(inputStream);
		assertNotNull("result == null", result);
	}

	/**
	 * Test storeImage(String,BufferedImage,ZipOutputStream).
	 */
	public void testStoreImage_null_name()
	{
		try {
			GameMapIO.storeImage(null, null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeImage(String,BufferedImage,ZipOutputStream).
	 */
	public void testStoreImage_null_image()
	{
		try {
			GameMapIO.storeImage("name", null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeImage(String,BufferedImage,ZipOutputStream).
	 */
	public void testStoreImage_null_stream()
	{
		try {
			GameMapIO.storeImage(
			        "name",
			        new BufferedImage(600, 800, BufferedImage.TYPE_4BYTE_ABGR),
			        null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeGeometry(String,Geometry,ZipOutputStream).
	 * 
	 * @throws IOException
	 */
	public void testStoreGeometry() throws IOException
	{
		// objects
		String name = "name";

		Geometry geometry =
		        new Geometry(600, 800, GridType.DIAMOND, 15);

		File zipFile = new File(getSandbox(), "testStoreGeometry.zip");
		ZipOutputStream zipOutputStream =
		        new ZipOutputStream(new FileOutputStream(zipFile));

		// test
		GameMapIO.storeGeometry(name, geometry, zipOutputStream);

		// verify
		zipOutputStream.close();

		ZipFile zip = new ZipFile(zipFile);
		ZipEntry entry =
		        zip.getEntry(GameMapIO.MAP_DIRECTORY + File.separator + name + "." + GameMapIO.MAP_GEOMETRY_EXTENSION);
		InputStream inputStream = zip.getInputStream(entry);
		Geometry result = GameMapIO.loadGeometry(inputStream);
		assertEquals("result != geometry", geometry, result);
	}

	/**
	 * Test storeGeometry(String,Geometry,ZipOutputStream).
	 */
	public void testStoreGeometry_null_name()
	{
		try {
			GameMapIO.storeGeometry(null, null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeGeometry(String,Geometry,ZipOutputStream).
	 */
	public void testStoreGeoemtry_null_geometry()
	{
		try {
			GameMapIO.storeGeometry("name", null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeGeometry(String,Geometry,ZipOutputStream).
	 */
	public void testStoreGeometry_null_stream()
	{
		try {
			GameMapIO.storeGeometry("name", new Geometry(), null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeLocations(String,Set<Location>,ZipOutputStream).
	 * 
	 * @throws IOException
	 */
	public void testStoreLocations() throws IOException
	{
		// objects
		String name = "name";
		Location a1 = new Location("a1", LocationType.CITY);
		a1.getCoordinates().add(new Coordinate(10, 10));

		Location a2 = new Location("a2", LocationType.FOREST);
		a2.getCoordinates().add(new Coordinate(20, 20));

		Set<Location> locations = new HashSet<Location>();
		locations.add(a1);
		locations.add(a2);

		File zipFile = new File(getSandbox(), "testStoreLocations.zip");
		ZipOutputStream zipOutputStream =
		        new ZipOutputStream(new FileOutputStream(zipFile));

		// test
		GameMapIO.storeLocations(name, locations, zipOutputStream);

		// verify
		zipOutputStream.close();

		ZipFile zip = new ZipFile(zipFile);
		ZipEntry entry =
		        zip.getEntry(GameMapIO.MAP_DIRECTORY + File.separator + name + "." + GameMapIO.MAP_LOCATIONS_EXTENSION);
		InputStream inputStream = zip.getInputStream(entry);
		Set<Location> result = GameMapIO.loadLocations(inputStream);
		assertEquals("result != locations", locations, result);
	}

	/**
	 * Test storeLocations(String,Set<Location>,ZipOutputStream).
	 */
	public void testStoreLocations_null_name()
	{
		try {
			GameMapIO.storeLocations(null, null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeLocations(String,Set<Location>,ZipOutputStream).
	 */
	public void testStoreLocations_null_locations()
	{
		try {
			GameMapIO.storeLocations("name", null, null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test storeLocations(String,Set<Location>,ZipOutputStream).
	 */
	public void testStoreLocations_null_stream()
	{
		try {
			GameMapIO.storeLocations("name",
			        new HashSet<Location>(), null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test loadImage(InputStream).
	 * 
	 * @throws IOException
	 */
	public void testLoadImage() throws IOException
	{
		// objects
		BufferedImage image =
		        new BufferedImage(600, 800, BufferedImage.TYPE_4BYTE_ABGR);

		// setup
		ByteArrayOutputStream outputStream =
		        new ByteArrayOutputStream();
		ImageIO.write(image, "png", outputStream);

		ByteArrayInputStream inputStream =
		        new ByteArrayInputStream(outputStream.toByteArray());

		// test
		BufferedImage result = GameMapIO.loadImage(inputStream);
		assertNotNull("result == null", result);
		// assume the image is the same
	}

	/**
	 * Test loadImage(InputStream).
	 */
	public void testLoadImage_null()
	{
		try {
			GameMapIO.loadImage(null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test loadGeometry(InputStream).
	 */
	public void testLoadGeometry()
	{
		// objects
		Geometry geometry =
		        new Geometry(600, 800, GridType.DIAMOND, 15);

		// setup
		ByteArrayOutputStream outputStream =
		        new ByteArrayOutputStream();
		XMLEncoder encoder = new XMLEncoder(outputStream);
		encoder.writeObject(geometry);
		encoder.close();

		ByteArrayInputStream inputStream =
		        new ByteArrayInputStream(outputStream.toByteArray());

		// test
		Geometry result = GameMapIO.loadGeometry(inputStream);
		assertNotNull("result == null", result);
		assertEquals("result != geometry", geometry, result);
	}

	/**
	 * Test loadGeometry(InputStream).
	 */
	public void testLoadGeometry_null()
	{
		try {
			GameMapIO.loadGeometry(null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}

	/**
	 * Test loadLocations(IGameMap,ZipInputStream)
	 */
	public void testLoadLocations()
	{
		// objects
		Location a1 = new Location("a1", LocationType.CITY);
		a1.getCoordinates().add(new Coordinate(10, 10));

		Location a2 = new Location("a2", LocationType.FOREST);
		a2.getCoordinates().add(new Coordinate(20, 20));

		Set<Location> locations = new HashSet<Location>();
		locations.add(a1);
		locations.add(a2);

		// setup
		ByteArrayOutputStream outputStream =
		        new ByteArrayOutputStream();
		XMLEncoder encoder = new XMLEncoder(outputStream);
		encoder.writeObject(locations);
		encoder.close();

		ByteArrayInputStream inputStream =
		        new ByteArrayInputStream(outputStream.toByteArray());

		// test
		try {
			Set<Location> result =
			        GameMapIO.loadLocations(inputStream);

			assertNotNull("result == null", result);
			assertEquals("result.size", 2, result.size());
		} catch (Exception e) {
			fail(e.toString());
		}
	}

	/**
	 * Test loadLocations(InputStream).
	 */
	public void testLoadLocations_null()
	{
		try {
			GameMapIO.loadLocations(null);
			assertUnreachable("Expected IllegalArgumentException");
		} catch (Exception e) {
			assertIsInstance("Expected IllegalArgumentException",
			        IllegalArgumentException.class, e);
		}
	}
}
